Exploring Qutebrowser 6:send weibo with commands

I'm exploring the source code of Qutebrowser. In this post, I will write a custom command to send a Weibo.

Core Steps

  1. create a custom command function
  2. get the user input by function parameter
  3. navigate current tab to target site
  4. find the inputarea, and input text
  5. click send!

Command Function

Most of the commands are under qutebrowser/browser/commands.py. So I will apend my code to this source file:

@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('content')
def weibo(self, content=None):
    # write my code here
    pass

The content parameter will contain the content input by the user.

Modify AbstractTab

I modified the source code of Qutebrowser AbstractTab, adding a listening callback mechanism to help commands listen for the completion of web page loading. In the AbstractTab class:

First add a class field:

on_load_finish_cbs: List[Callable[[bool], None]] = []

Then in the _on_load_finished method, add the following code:

@pyqtSlot(bool)
def _on_load_finished(self, ok: bool) -> None:
	assert self._widget is not None
	if self.is_deleted():
		# https://github.com/qutebrowser/qutebrowser/issues/3498
		return

	# the code to add
	for cb in self.on_load_finish_cbs:
		cb(ok)

	#...

The CommandDispatcher provides a _cntwidget method to get current browser tab. Then we call the load_url to navigate our tab to Weibo Website.

@cmdutils.register(instance='command-dispatcher', scope='window')
@cmdutils.argument('content')
def weibo(self, content=None):
    cur_tab: browsertab.AbstractTab = self._cntwidget()

    def on_load_finish(ok: bool):
        cur_tab.on_load_finish_cbs.remove(on_load_finish)
        print('on_load_finish')

    cur_tab.on_load_finish_cbs.append(on_load_finish)
    cur_tab.load_url(QUrl('https://weibo.com'))

When the page is loaded, the on_load_finish will be called.

Finding the Inputarea

In the on_load_finish method, I added the following code to find the inputarea. When it was found, I use the insert_text method of AbstractWebElement for inputing.

def on_load_finish(ok: bool):
    print(f'on_load_finish {cur_tab.url().toString()}')
    cur_tab.on_load_finish_cbs.remove(on_load_finish)

    selector = webelem.css_selector('inputs', url)
    print(f'css selector: {selector}')

    def on_find_input(elems: Sequence[AbstractWebElement]):
        for elem in elems:
            classes = elem.classes()
            found = False
            for cls in classes:
                if cls.startswith('Form_input'):
                    found = True
                    break
            if not found:
                continue
            elem.insert_text(content)
            print(f'find input: {elem.outer_xml()}')
            # elem.insert_text(content)

    cur_tab.elements.find_css(
        selector,
        on_find_input,
        lambda e: print(f'find input error: {e}'))

Clicking Send

First we need to find the click button. We will use the QuteBrowser's css_selector method again.

def on_find_send(send_elems: Sequence[AbstractWebElement]):
    send_template = '<span class="woo-button-content">发送</span>'
    for send_elem in send_elems:
        send_classes = send_elem.classes()
        send_found = False
        for _ in send_classes:
            if send_template in send_elem.outer_xml():
                send_found = True
                break
        if not send_found:
            continue
        send_elem.click(usertypes.ClickTarget.normal)

selector_send = webelem.css_selector('all', url)
cur_tab.elements.find_css(
    selector_send,
    on_find_send,
    lambda e: print(f'find send error: {e}'))

The code is almost the same. I use a piece of HTML code to identify the send button. I think there's a better way to find the button, but the code above just works :)

Bingo!

Pasted image 20231116013604.png

It's very cool! If you want to create a command for Twitter/X, It's the same way. See you at my next blog!


本文作者:Maeiee

本文链接:Exploring Qutebrowser 6:send weibo with commands

版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!


喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!